<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>投掷</title>
    <style>
      #box {
        position: absolute;
        left: 0;
        top: 0;
        width: 100px;
        height: 100px;
        background: red;
      }
    </style>
  </head>
  <body>
    <div id="box"></div>

    <script>
      const dragBox = document.querySelector("#box");
      start(dragBox, ({ x, y }) => {
        console.log(x, y);
      });

      function start(dragBox, callback) {
        let disX = 0,
          disY = 0;

        let prevX = 0,
          prevY = 0;
        let isSpeedX,
          isSpeedY = 0;

        let timer = null;
        let lastTime = null;
        const gravity = 0.98;
        const airResistance = 0.99;
        const damping = 0.75;

        dragBox.onmousedown = (ev) => {
          ev.preventDefault();

          if (timer) {
            clearInterval(timer);
            timer = null;
          }

          disX = ev.clientX - dragBox.offsetLeft;
          disY = ev.clientY - dragBox.offsetTop;

          prevX = ev.clientX;
          prevY = ev.clientY;

          lastTime = Date.now();

          document.onmousemove = (ev) => {
            ev.preventDefault();
            const currentX = ev.clientX - disX;
            const currentY = ev.clientY - disY;

            const deltaX = ev.clientX - prevX;
            const deltaY = ev.clientY - prevY;

            dragBox.style.left = `${currentX}px`;
            dragBox.style.top = `${currentY}px`;

            const currentTime = Date.now();
            const deltaTime = currentTime - lastTime;

            if (deltaTime > 0) {
              // x 轴方向的速度
              const speedX = (deltaX / deltaTime) * 100;
              // y 轴方向的速度
              const speedY = (deltaY / deltaTime) * 100;
              // 合速度
              let speed = Math.sqrt(speedX ** 2 + speedY ** 2);

              speed = speed > damping ? speed - damping : 0;

              // 计算角度(速度方向)
              const angle = Math.atan2(speedY, speedX);

              isSpeedX = speed * Math.cos(angle);
              isSpeedY = speed * Math.sin(angle);
            }

            prevX = ev.clientX;
            prevY = ev.clientY;
          };
          document.onmouseup = (ev) => {
            ev.preventDefault();
            document.onmousemove = null;
            document.onmouseup = null;

            startMove();
          };
        };

        const _L = document.documentElement.clientWidth - dragBox.offsetWidth;
        const _T = document.documentElement.clientHeight - dragBox.offsetHeight;

        function startMove() {
          clearInterval(timer);

          timer = setInterval(() => {
            // 重力加速,落下
            isSpeedY += gravity;

            // 阻尼
            isSpeedX *= airResistance;
            isSpeedY *= airResistance;

            let L = dragBox.offsetLeft + isSpeedX;
            let T = dragBox.offsetTop + isSpeedY;

            if (T > _T) {
              T = _T;

              // 改变方向
              isSpeedY *= -1;

              // 摩擦力减速
              isSpeedY *= damping;
              isSpeedX *= damping;
            } else if (T < 0) {
              T = 0;
              // 改变方向
              isSpeedY *= -1;

              // 摩擦力减速
              isSpeedY *= damping;
            }

            if (L > _L) {
              L = _L;

              // 改变方向
              isSpeedX *= -1;

              // 摩擦力减速
              isSpeedX *= damping;
            } else if (L < 0) {
              L = 0;
              // 改变方向
              isSpeedX *= -1;

              // 摩擦力减速
              isSpeedX *= damping;
            }

            dragBox.style.left = `${L}px`;
            dragBox.style.top = `${T}px`;

            // console.log(isSpeedX, isSpeedY);
            // 停止条件
            if (Math.abs(isSpeedX) < 0.5 && Math.abs(isSpeedY) < 0.5) {
              clearInterval(timer);
              timer = null;
              console.log("停止");

              callback && callback({ x: L, y: T });
            }
          }, 1000 / 30);
        }
      }
    </script>
  </body>
</html>
